﻿using System;
using System.Collections.Generic;
using CoreEx.Common.Data;
using CoreEx.Common.Mediator;

namespace CoreEx.Common.Implementation.Mediator
{
    public class Mediator : IMediator
    {
        private IDictionary<SurrogateKey, IList<WeakAction>> _invocationList =
            new Dictionary<SurrogateKey, IList<WeakAction>>();

        /// <summary>
        /// Publishes a new message to all subscribers.
        /// </summary>
        /// <typeparam name="T">The <see cref="Type"/> of parameter to be passed along with the message.</typeparam>
        /// <param name="message">The message to publish</param>
        /// <param name="value">The argument to be passed along with the <paramref name="message"/>.</param>
        public void Publish<T>(string message, T value)
        {
            var surrogateKey = new SurrogateKey(new object[] {message, typeof (T)});            
            if (_invocationList.ContainsKey(surrogateKey))
            {
                var actions = _invocationList[surrogateKey];
                for (int i = actions.Count - 1; i > - 1; i--)
                {
                    var action = actions[i];
                    if (action.IsAlive)
                        action.Invoke(value);
                    else
                        actions.RemoveAt(i);
                }
            }            
        }

        /// <summary>
        /// Subscribes to a message. 
        /// </summary>
        /// <typeparam name="T">The <see cref="Type"/> of parameter sent by the publisher.</typeparam>
        /// <param name="message">The message to subscribe to.</param>
        /// <param name="callback">The delegate that will be invoked when messages are received.</param>
        public void Subscribe<T>(string message, Action<T> callback)
        {                        
            var surrogateKey = new SurrogateKey(new object[] { message, typeof(T) });
            if (!_invocationList.ContainsKey(surrogateKey))
                _invocationList.Add(surrogateKey,new List<WeakAction>());
            _invocationList[surrogateKey].Add(new WeakAction(callback));                        
        }
    }
}
